unit RunProperties;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, ExtCtrls, StdCtrls, ComCtrls, ValEdit, parameter, Index, XTASACS,
  surveyindexdlg, math, ifmtextspoolerunit, StdActns, ActnList, clipbrd, tasacsconfigtypes;

type
  TfrmRunProperties = class(TForm)
    PageControl1 : TPageControl;
    tsIndex : TTabSheet;
    lblStockTitle : TLabel;
    lblFiles : TLabel;
    ebStockTitle : TEdit;
    VlInFiles: TValueListEditor;
    gbPopModel : TGroupBox;
    lblFirstYear : TLabel;
    lblLastYear : TLabel;
    lblModelType : TLabel;
    lblPlusgroupMethod : TLabel;
    lblFirstAge : TLabel;
    lblLastAge : TLabel;
    lblLastRefAge : TLabel;
    Label6 : TLabel;
    ebFirstYear : TEdit;
    ebLastYear : TEdit;
    cbModelType : TComboBox;
    cbPlusgroupMethod : TComboBox;
    ebLastAge : TEdit;
    ebFirstAge : TEdit;
    ebFirstRefAge : TEdit;
    ebLastRefAge : TEdit;
    gbObjectFunction : TGroupBox;
    lvIndices : TListView;
    btnEdit : TButton;
    tsParameters : TTabSheet;
    Label1 : TLabel;
    lblSurveyIndex : TLabel;
    lblParamText : TLabel;
    Label4 : TLabel;
    cbCategory : TComboBox;
    cbIndex : TComboBox;
    rgView : TRadioGroup;
    sgParam : TStringGrid;
    ebParamText : TEdit;
    cbFlag : TComboBox;
    btnok : TButton;
    btnCancel : TButton;
    gbOptimization : TGroupBox;
    cbSearchRoutine : TComboBox;
    ActionList1 : TActionList;
    EditCopy1 : TEditCopy;
    EditPaste1 : TEditPaste;
    btnDataSourceAdd: TButton;
    btnDelete: TButton;
    GroupBox1: TGroupBox;
    ebNumMedElms: TEdit;
    lblNumMedElms: TLabel;
    GroupBox2: TGroupBox;
    cbProcessType: TComboBox;
    lblNumStages: TLabel;
    ebNumStages: TEdit;
    Label7: TLabel;
    ebParamInFile: TEdit;
    Label8: TLabel;
    vlOutFiles: TValueListEditor;
    lblISVPAControl: TLabel;
    cbISVPAControl: TComboBox;
    lblLastCatchYear: TLabel;
    ebLastCatchYear: TEdit;
    Label2: TLabel;
    ebSSBFracF: TEdit;
    ebSSBFracM: TEdit;
    Label3: TLabel;
    procedure sgParamDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure sgParamGetEditText(Sender: TObject; ACol, ARow: Integer;
      var Value: string);
    procedure sgParamKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure sgParamKeyPress(Sender: TObject; var Key: Char);
    procedure sgParamKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure sgParamSelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure sgParamSetEditText(Sender: TObject; ACol, ARow: Integer;
      const Value: string);
    procedure cbCategoryClick(Sender: TObject);
    procedure cbIndexClick(Sender: TObject);
    procedure rgViewClick(Sender: TObject);
    procedure cbFlagClick(Sender: TObject);
    procedure ebParamTextChange(Sender: TObject);
    procedure btnDeleteClick(Sender: TObject);
    procedure btnEditClick(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure tsIndexContextPopup(Sender: TObject; MousePos: TPoint;
      var Handled: Boolean);
    procedure btnokClick(Sender: TObject);
    procedure EditCopy1Execute(Sender: TObject);
    procedure EditCopy1Update(Sender: TObject);
    procedure EditPaste1Execute(Sender: TObject);
    procedure cbProcessTypeClick(Sender: TObject);
    procedure VlInFilesStringsChange(Sender: TObject);
    procedure EditPaste1Update(Sender: TObject);
  private
      m_SelTargetCol, m_SelTargetRow : Integer;
      m_RegisterSelTarget : Boolean;

      procedure ApplyIndexInput;
      procedure MapTableIndex(ACol, ARow : Integer; var Cat, iIndex, iYear, iAge : integer);
      procedure UpdateParametersPage(DoFocus : Boolean);
//      function GetParamElm(ACol, ARow : Integer) : TParamElmPtr; overload;
      function GetParamElmValue(ACol, ARow : Integer) : double;
      function GetParamElmFlag(ACol, ARow : Integer) : Integer;
      function GetParamElmDescr(ACol, ARow : Integer) : string;
      procedure SetParamElmValue(ACol, ARow : Integer; Value : double);
      procedure SetParamElmFlag(ACol, ARow : Integer; Value : Integer);
      procedure SetParamElmDescr(ACol, ARow : Integer; Value : string);
      function CanSelectCell(ACol, ARow: Integer) : Boolean;
      function GetSelectedCategory : Integer;
      procedure UpdateStructure;
//      function GetModeValue(pParamElm : TParamElmPtr) : double;
//      procedure SetModeValue(pParamElm : TParamElmPtr; Value : double);
      procedure OptimizeSize;
      function GetSelectionLeft : Integer;
      function GetSelectionTop : Integer;
      function GetSelectionRight : Integer;
      function GetSelectionBottom : Integer;
      procedure FixListNumbering();
   protected
      destructor Destroy; override;
    { Private declarations }
  public
    { Public declarations }
  end;

function GetDataSource(DataSource, DataSourceIndex : Integer) : TDataSource;

implementation

{$R *.dfm}

const moValue = 0;
const moFlag = 1;


destructor TfrmRunProperties.Destroy;
var
   I : Integer;
begin
   for I := 0 to lvIndices.items.count - 1 do
      TObject(lvIndices.Items[I].Data).Free;
   inherited;
end; // TfrmRunProperties.Destroy


procedure CopyDataSource(Source : TDataSource; var Target : TDataSource);
begin
//   Target.Weight := Source.Weight;
   Target.fprop := Source.fprop;
   Target.mprop := Source.mprop;
   Target.weight := Source.weight;
   Target.objtype := Source.objtype;
   Target.my := Source.my;
   Target.PlusGroupCode := Source.PlusGroupCode;
   Target.BootType := Source.BootType;
   Target.Sigma := Source.Sigma;
   Target.BootFile := Source.BootFile;
end;


procedure TfrmRunProperties.FixListNumbering();
var
   I, J : Integer;
   NumCanum, NumFleets, NumSSB, NumBiomass : Integer;
   li : TListItem;
   ds : TDataSourceObj;
begin
   NumCanum := 0;
   NumFleets := 0;
   NumSSB := 0;
   NumBiomass := 0;
   for I := 0 to lvIndices.Items.count - 1 do
   begin
      li := lvIndices.items[I];
      ds := TDataSourceObj(li.data);
      case(ds.ObservedDataType) of
         odCanum:
         begin
            NumCanum := NumCanum + 1;
            J := NumCanum;
         end;
         odFleet:
         begin
            NumFleets := NumFleets + 1;
            J := NumFleets;
         end;
         odSSB:
         begin
            NumSSB := NumSSB + 1;
            J := NumSSB;
         end;
         odBiomass:
         begin
            NumBiomass := NumBiomass + 1;
            J := NumBiomass;
         end;
      end; // case
      li.Caption := inttostr(J) + '. ' + ObservedDataTypeDescr(ds.ObservedDataType);
   end;
end;


procedure CopyDataSourceToListItem(ds : TDataSourceObj; li : TListItem);
var
   I : Integer;
begin
   if li.subitems.count = 0 then
      for I := 0 to 9 - 1 do
         li.SubItems.Add('');

   li.Caption := '';
//   li.SubItems[0] := floattostr(si.Index.Weight);
   li.SubItems[0] := floattostr(ds.DataSource.FProp);
   li.SubItems[1] := floattostr(ds.DataSource.MProp);
   li.SubItems[2] := ObjTypeDescr(ds.DataSource.ObjType);
   li.SubItems[3] := floattostr(ds.DataSource.Weight);
   li.SubItems[4] := floattostr(ds.DataSource.My);
   case ds.DataSource.PlusGroupCode of
      1: li.SubItems[5] := 'P';
   else
      li.SubItems[5] := '';
   end; // case
   li.SubItems[6] := BootTypeDescr(ds.DataSource.BootType);
   li.SubItems[7] := floattostr(ds.DataSource.Sigma);
   li.SubItems[8] := ds.DataSource.BootFile;
   li.data := pointer(ds);
end; // CopyDataSourceToListItem


function GetDataSourceNumberFromListNumber(iListNumber : Integer) : Integer;
var
   NumFleets, NumSSB, NumBiomass : Integer;
begin
   NumFleets := round(get_Run_Prop(propNumFleetIndices));
   NumSSB := round(get_Run_Prop(propNumSSBIndices));
   NumBiomass := round(get_Run_Prop(propNumBiomassIndices));
   Result := iListNumber;
   if 0 < Result then
   begin
      Result := Result - 1;
      if NumFleets - 1 < Result then
      begin
         Result := Result - NumFleets;
         if NumSSB - 1 < Result then
            Result := Result - NumSSB;
      end
   end
end; // GetDataSourceNumberFromListNumber


procedure TfrmRunProperties.btnAddClick(Sender: TObject);
var
   ds : TDataSourceObj;
   li : TListItem;
begin
   ds := TDataSourceObj.Create;
   ds.ObservedDataType := odFleet;
//   si.Index.Weight := 0;
   ds.DataSource.FProp := 0;
   ds.DataSource.MProp := 0;
   ds.DataSource.ObjType := 0;
   ds.DataSource.Weight := 1.0;
   ds.DataSource.My := 0.001;
   li := lvIndices.Items.Add;
   if CreateSurveyIndexDlg(Self, ds) then
      CopyDataSourceToListItem(ds, li)
   else
      ds.Free;
   FixListNumbering();
end; // TfrmRunProperties.btnAddClick


procedure TfrmRunProperties.btnDeleteClick(Sender: TObject);
var
   ds : TDataSourceObj;
   li : TListItem;
begin
   li := lvIndices.Selected;
   if li <> nil then
   begin
      ds := TDataSourceObj(lvIndices.Selected.Data);
      ds.Free;
      li.Free;
   end;
   FixListNumbering();
end; // TfrmRunProperties.btnDeleteClick


procedure TfrmRunProperties.btnEditClick(Sender: TObject);
var
   ds : TDataSourceObj;
   li : TListItem;
begin
   li := lvIndices.Selected;
   if li <> nil then
   begin
      ds := TDataSourceObj(lvIndices.Selected.Data);
      if CreateSurveyIndexDlg(Self, ds) then
      begin
         CopyDataSourceToListItem(ds, li);
      end
   end;
   FixListNumbering();
end; // TfrmRunProperties.btnEditClick


procedure TfrmRunProperties.btnokClick(Sender: TObject);
begin
  ApplyIndexInput;
end; // TfrmRunProperties.btnokClick


procedure TfrmRunProperties.cbCategoryClick(Sender: TObject);
begin
   UpdateParametersPage(true);
end; // TfrmRunProperties.cbCategoryClick


const c_Flags : array[0..4] of Integer = (0, 1, 2, -1, 3);


procedure TfrmRunProperties.cbFlagClick(Sender: TObject);
var
   iCol, iRow : Integer;
//   pParamElm : TParamElmPtr;
begin
   if not g_RunIsLoaded then
      exit;
   for iRow := GetSelectionTop to GetSelectionBottom do
   begin
      for iCol := GetSelectionLeft to GetSelectionRight do
      begin
//         pParamElm := GetParamElm(iCol, iRow);
//         pParamElm^.Flag := c_Flags[cbFlag.ItemIndex];
           SetParamElmFlag(iCol, iRow, c_Flags[cbFlag.ItemIndex]);
      end; // for
   end; // for
   OptimizeSize;
end; // TfrmRunProperties.cbFlagClick


procedure TfrmRunProperties.cbIndexClick(Sender: TObject);
begin
   UpdateStructure;
end; // TfrmRunProperties.cbIndexClick


procedure TfrmRunProperties.cbProcessTypeClick(Sender: TObject);
begin
   ebNumStages.Enabled := cbProcessType.ItemIndex in [ptBootstrap, ptRetrospectiveRun];
   case cbProcessType.ItemIndex of
      ptOrdinaryAssessment, ptSingleModelRun:
         ebNumStages.Text := inttostr(1);
      ptBootstrap:
         ebNumStages.Text := inttostr(1000);
      ptRetrospectiveRun:
         ebNumStages.Text := inttostr(5);
      ptParameterPertubation:
   end; // case
end; // TfrmRunProperties.cbProcessTypeClick


function SafeStrToFloatEx(str : string; Def : double; Sep : char) : double;
var
   fs : TFormatSettings;
begin
   FillChar(fs, sizeof(TFormatSettings), #0);
   fs.DecimalSeparator := sep;
   Result := Def;
   TryStrToFloat(trim(Str), Result, fs);
end; // SafeStrToFloatEx


function SafeStrToFloat(Str : string) : Double;
begin
   Result := SafeStrToFloatEx(Str, 0, DecimalSeparator);
end; // SafeStrToFloat


procedure TfrmRunProperties.ebParamTextChange(Sender: TObject);
//var
//   pParamElm : TParamElmPtr;
begin
   with sgParam do
   begin
(*      pParamElm := GetParamElm(Col, Row);
      if pParamElm <> nil then
      begin
         strcopy(pchar(@pParamElm^.Descr[1]), pchar(ebParamText.Text));
      end;*)
      SetParamElmDescr(Col, Row, ebParamText.Text);
   end; // with
end;


function GetDataSource(DataSource, DataSourceIndex : Integer) : TDataSource;
begin
   with Result do
      get_DataSource(DataSource, DataSourceIndex, FProp, MProp, ObjType, Weight, My, PlusGroupCode, BootType, Sigma, BootFile);
end; // GeTDataSource


procedure TfrmRunProperties.FormCreate(Sender: TObject);
   procedure AddSurveyIndexToList(_Type : Integer; DataSource : TDataSource; J : Integer);
   var
      ds : TDataSourceObj;
   begin
      ds := TDataSourceObj.Create;
      ds.ObservedDataType := _Type;
      CopyDataSource(DataSource, ds.DataSource);
      CopyDataSourceToListItem(ds, lvIndices.Items.Add)
   end; // AddSurveyIndexToList
var
   I, Cat : Integer;
begin
   if not g_RunIsLoaded then
      exit;
   m_SelTargetCol := -1;
   m_SelTargetRow := -1;
   m_RegisterSelTarget := false;
   // Setup category
   for Cat := cFirstCategory to cLastCategory do
      cbCategory.Items.AddObject(get_categoryname(Cat), Pointer(Cat));
   cbCategory.ItemIndex := 0;
   PageControl1.TabIndex := 0;
   UpdateParametersPage(false);
   ebStockTitle.Text := get_IndexInput_StockTitle();

   cbSearchRoutine.ItemIndex := round(get_Run_Prop(propSearchRoutine));
   cbProcessType.ItemIndex := round(get_Run_Prop(propProcessType));
   cbProcessTypeClick(nil);
   ebNumStages.Text := inttostr(round(get_Run_Prop(propNumStages)));
   cbModelType.ItemIndex := round(get_Run_Prop(propModelType));
   cbISVPAControl.ItemIndex := round(get_Run_Prop(propISVPAControlType));
   cbPlusGroupMethod.ItemIndex := round(get_Run_Prop(propPlusGroupMethod));
   ebFirstYear.Text := inttostr(round(get_Run_Prop(propFirstYear)));
   ebLastYear.Text := inttostr(round(get_Run_Prop(propLastYear)));
   ebLastCatchYear.Text := inttostr(round(get_Run_Prop(propLastCatchYear)));
   ebFirstAge.Text := inttostr(round(get_Run_Prop(propFirstAge)));
   ebLastAge.Text := inttostr(round(get_Run_Prop(propLastAge)));
   ebFirstRefAge.Text := inttostr(round(get_Run_Prop(propFirstRefAge)));
   ebLastRefAge.Text := inttostr(round(get_Run_Prop(propLastRefAge)));
   ebNumMedElms.Text := inttostr(round(get_Run_Prop(propNumMedianElms)));
   ebSSBFracF.Text := floattostr(get_Run_Prop(propSSBFracF));
   ebSSBFracM.Text := floattostr(get_Run_Prop(propSSBFracM));
//   ebGammaShape.Text := floattostr(get_Run_Prop(propGammaShape));
//   ebCatchWeight.Text := floattostr(g_pIndexInput^.CatchWeight);

   vlInFiles.Cells[1, 1] := get_Run_Prop_Str(propParamInFile);
   vlInFiles.Cells[1, 2] := get_Run_Prop_Str(propCaNumWeightFile);
   vlInFiles.Cells[1, 3] := get_Run_Prop_Str(propFleetWeightFile);
   vlInFiles.Cells[1, 4] := get_Run_Prop_Str(propSSBWeightFile);
   vlInFiles.Cells[1, 5] := get_Run_Prop_Str(propBiomassWeightFile);

   for I := propParamOutFile to propRetroRecruitFile do
      vlOutFiles.Cells[1, I - propParamOutFile + 1] := get_Run_Prop_Str(I);

   AddSurveyIndexToList(odCanum, GetDataSource(odCanum, 0), 0);
   for I := 0 to round(get_Run_Prop(propNumFleetIndices)) - 1 do
      AddSurveyIndexToList(odFleet, GetDataSource(odFleet, I), I);
   for I := 0 to round(get_Run_Prop(propNumSSBIndices)) - 1 do
      AddSurveyIndexToList(odSSB, GetDataSource(odSSB, I), I);
   for I := 0 to round(get_Run_Prop(propNumBiomassIndices)) - 1 do
      AddSurveyIndexToList(odBiomass, GetDataSource(odBiomass, I), I);

   // trigger event
   if PageControl1.TabIndex = 1 then
      cbCategoryClick(nil);
   FixListNumbering();
end; // TfrmRunProperties.FormCreate


procedure TfrmRunProperties.rgViewClick(Sender: TObject);
begin
   if not g_RunIsLoaded then
      exit;
   OptimizeSize;
end;


// TfrmRunProperties.cbIndexClick
procedure TfrmRunProperties.sgParamDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
  procedure WriteText(StringGrid: TStringGrid; ACanvas: TCanvas; const ARect: TRect; const Text: string; Format: Word; CellColor : TColor);
  const
    DX = 2;
    DY = 2;
   var
    oldPenColor : TColor;
    InLastAge, InLastYear : Boolean;
    _Focused, _Selected : Boolean;
//    pParam : TParamElmPtr;
  begin
    with Stringgrid, ACanvas, ARect do
    begin
      _Focused := (ARow = Row) and (ACol = Col);
      _Selected := (GetSelectionLeft <= ACol) and (ACol <= GetSelectionRight) and
         (GetSelectionTop <= ARow) and (ARow <= GetSelectionBottom);
      if not _Focused and _Selected then
         Brush.Color := clHighlight
      else if not CanSelectCell(ACol, ARow) then
         Brush.Color := $eeeeee
      else
      begin
         Brush.Color := CellColor;
         if (0 < ARow) and (0 < ACol) then
         begin
            case GetParamElmFlag(ACol, ARow) of
               1: Brush.Color := $ddffdd;
               2: Brush.Color := $ddffff;
               -1: Brush.Color := $ffffdd;
               3: Brush.Color := $ffcce6;
            end; // case
         end;
      end;
      FillRect(Rect);
      try
      if Text = '' then
         exit;
      ACanvas.Font.Assign(Stringgrid.Font);
      if not _Focused and _Selected then
      begin
         Font.Color := clHighlightText;
      end
      else
         Font.Color := clWindowText;

      case Format of
        DT_LEFT: ExtTextOut(Handle, Left + DX, Top + DY,
            ETO_OPAQUE or ETO_CLIPPED, @ARect, PChar(Text), Length(Text), nil);

        DT_RIGHT: ExtTextOut(Handle, Right - TextWidth(Text) - 3, Top + DY,
            ETO_OPAQUE or ETO_CLIPPED, @ARect, PChar(Text),
            Length(Text), nil);

        DT_CENTER: ExtTextOut(Handle, Left + (Right - Left - TextWidth(Text)) div 2,
            Top + DY, ETO_OPAQUE or ETO_CLIPPED, @ARect,
            PChar(Text), Length(Text), nil);
      end;
      finally
      oldpencolor := Pen.Color;
      Pen.Color := clBlack;
(*      InLastAge := (GetSelectedCategory = cNLastAge) and (ACol = ColCount - 2) and (ARow < RowCount - 1);
      InLastYear := (GetSelectedCategory = cNLastYear) and (ARow = RowCount - 1) and (ACol < ColCount - 1);
      if InLastAge then
      begin
         // Left line
         MoveTo(Rect.Left - 1, Rect.Top);
         LineTo(Rect.Left - 1, Rect.Bottom);
         // Right line
         MoveTo(Rect.Right, Rect.Top);
         LineTo(Rect.Right, Rect.Bottom);
      end;
      if InLastYear then
      begin
         // Upper line
         MoveTo(Rect.Left, Rect.Top - 1);
         LineTo(Rect.Right, Rect.Top - 1);
         // Lower line
         MoveTo(Rect.Left, Rect.Bottom);
         LineTo(Rect.Right, Rect.Bottom);
      end;*)
      if sgParam.Focused and _Selected then
      begin
         if ACol = GetSelectionLeft then
         begin
            Canvas.MoveTo(Rect.Left, Rect.Top);
            Canvas.LineTo(Rect.Left, Rect.Bottom);
         end;
         if ACol = GetSelectionRight then
         begin
            Canvas.MoveTo(Rect.Right, Rect.Top);
            Canvas.LineTo(Rect.Right, Rect.Bottom);
         end;
         if ARow = GetSelectionTop then
         begin
            Canvas.MoveTo(Rect.Left, Rect.Top);
            Canvas.LineTo(Rect.Right, Rect.Top);
         end;
         if ARow = GetSelectionBottom then
         begin
            Canvas.MoveTo(Rect.Left, Rect.Bottom);
            Canvas.LineTo(Rect.Right, Rect.Bottom);
         end;
      end; // end if
      Pen.Color := oldPencolor;
      end;
    end;
  end;

  procedure Display(StringGrid: TStringGrid; const S: string; Alignment: TAlignment; CellColor : TColor);
  const
    Formats: array[TAlignment] of Word = (DT_LEFT, DT_RIGHT, DT_CENTER);
  begin
    WriteText(StringGrid, StringGrid.Canvas, Rect, S, Formats[Alignment], CellColor);
  end;
var
   s : string;
   CellColor : TColor;
begin
   if not g_RunIsLoaded then
      exit;
   sgParamGetEditText(nil, ACol, ARow, s);
   if (ARow = 0) or (Acol = 0) then
      CellColor := clBtnFace
   else
      CellColor := clWindow;
   Display(sgParam, s, taRightJustify, CellColor)
end; // TfrmRunProperties.sgParamDrawCell


procedure TfrmRunProperties.sgParamSetEditText(Sender: TObject; ACol,
  ARow: Integer; const Value: string);
var
   Val : double;
begin
   if (0 < ARow) and (0 < ACol) then
   begin
      Val := safestrtofloat(Value);
      if rgView.ItemIndex = moFlag then
      begin
         Val := round(Val);
         case round(Val) of
            flKeepFixed, flEstimate, flEqualPrevYear, flEqualPrevAge,flSpecialCode:;
         else
            exit;
         end; // case
      end;
      // Map table index to structure index
//      SetModeValue(GetParamElm(ACol, ARow), safestrtofloat(Value));
      case rgView.ItemIndex of
         moValue: SetParamElmValue(ACol, ARow, safestrtofloat(Value));
         moFlag: SetParamElmFlag(ACol, ARow, round(Val));
      end; // case
   end;
end; // TfrmRunProperties.sgParamSetEditText


procedure TfrmRunProperties.tsIndexContextPopup(Sender: TObject;
  MousePos: TPoint; var Handled: Boolean);
begin

end;

// TfrmRunProperties.sgParamSetEditText

procedure TfrmRunProperties.sgParamGetEditText(Sender: TObject; ACol,
  ARow: Integer; var Value: string);
begin
   Value := '';
   if not sgParam.Enabled then
      exit;
   if (ARow = 0) and (ACol = 0) then
   begin
      case GetSelectedCategory of
         cNValues, cSelection, cNatMort, cCBL_Fac_Fleet, cCBL_Pow_Fleet:
            Value := 'Year/Age';
         cFYearFactor, cCBL_Fac_SSB, cCBL_Fac_BM, cCBL_Pow_SSB, cCBL_Pow_BM:
            Value := 'Year';
         cGamma_Canum..cGamma_BM:
            Value := '';
      end; // case
   end
   else if ARow = 0 then
   begin
      if (ARow = sgParam.RowCount - 1) and (GetSelectedCategory in [
         cNValues, cSelection, cNatMort, cCBL_Fac_Fleet, cCBL_Pow_Fleet]) then
         Value := inttostr(round(get_Run_Prop(propLastAge))) + '+'
      else
         case GetSelectedCategory of
            cNValues, cSelection, cNatMort, cCBL_Fac_Fleet, cCBL_Pow_Fleet:
               Value := inttostr(round(get_Run_Prop(propFirstAge)) + ACol - 1);
            cFYearFactor,
            cCBL_Fac_SSB,
            cCBL_Fac_BM,
            cCBL_Pow_SSB,
            cCBL_Pow_BM,
            cGamma_Canum..cGamma_BM:
            begin
               if rgView.ItemIndex = moValue then
                  Value := 'Value'
               else
                  Value := 'Flag'
            end
         end; // case
   end
   else if ACol = 0 then
      case GetSelectedCategory of
         cGamma_Canum..cGamma_BM:
            Value := ''
      else
         Value := inttostr(round(get_Run_Prop(propFirstYear)) + ARow - 1)
      end // case
   else
   begin
      if CanSelectCell(ACol, ARow) then
      begin
//         Value := floattostr(GetModeValue(GetParamElm(ACol, ARow)));
         case rgView.ItemIndex of
            moValue: Value := floattostr(GetParamElmValue(ACol, ARow));
            moFlag: Value := inttostr(GetParamElmFlag(ACol, ARow));
         end; // case
      end;
   end;
end; // TfrmRunProperties.sgParamGetEditText


procedure TfrmRunProperties.sgParamKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
   if sgParam.EditorMode and (Key in [VK_LEFT, VK_RIGHT]) then
   begin
      sgParam.EditorMode := false;
      case Key of
         VK_LEFT: sgParam.Col := max(0, sgParam.Col - 1);
         VK_RIGHT: sgParam.Col := min(sgParam.ColCount - 1, sgParam.Col + 1)
      end; // case
   end;
end; // TfrmRunProperties.sgParamKeyDown


procedure TfrmRunProperties.sgParamKeyPress(Sender: TObject;
  var Key: Char);
begin
   if Key = ',' then
      Key := DecimalSeparator;
end; // TfrmRunProperties.sgParamKeyPress


procedure TfrmRunProperties.sgParamKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
   if Key = VK_SHIFT then
   begin
      m_RegisterSelTarget := false;
   end;
end; // TfrmRunProperties.sgParamKeyUp


procedure TfrmRunProperties.sgParamSelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
var
//   pParamPtr : TParamElmPtr;
   _OnChange : TNotifyEvent;
   ShiftIsPressed : Boolean;
   _CanSelect : Boolean;
   I : Integer;
begin
   ShiftIsPressed := (0 <> (GetKeyState(VK_LSHIFT) and $FF00)) or (0 <> (GetKeyState(VK_RSHIFT) and $FF00));
   _CanSelect := CanSelectCell(ACol, ARow);
   CanSelect := _CanSelect;
   if CanSelect then
   begin
      if ShiftIsPressed then
      begin
         if not m_RegisterSelTarget then
         begin
            m_SelTargetCol := sgParam.Col;
            m_SelTargetRow := sgParam.Row;
            m_RegisterSelTarget := true;
         end;
      end
      else
      begin
         m_SelTargetCol := ACol;
         m_SelTargetRow := ARow;
      end;
//      pParamPtr := GetParamElm(ACol, ARow);
      _OnChange := ebParamText.OnChange;
      ebParamText.OnChange := nil;
      ebParamText.Text := GetParamElmDescr(ACol, ARow);
      ebParamText.OnChange := _OnChange;
      for I := low(c_Flags) to high(c_Flags) do
         if c_Flags[I] = GetParamElmFlag(ACol, ARow) then
         begin
            cbFlag.ItemIndex := I;
            break;
         end;
   end;
   sgParam.Invalidate;
//   sgParam.Update;
end; // TfrmRunProperties.sgParamSelectCell


procedure TfrmRunProperties.ApplyIndexInput;
var
   li : TListItem;
   ds : TDataSourceObj;
   DataSourceIndex, NumFleetIndices, NumSSBIndices, NumBiomassIndices : Integer;
   I : Integer;
begin
   set_Run_Prop_Str(propParamInFile, vlInFiles.Cells[1, 1]);
   set_Run_Prop_Str(propCaNumWeightFile, vlInFiles.Cells[1, 2]);
   set_Run_Prop_Str(propFleetWeightFile, vlInFiles.Cells[1, 3]);
   set_Run_Prop_Str(propSSBWeightFile, vlInFiles.Cells[1, 4]);
   set_Run_Prop_Str(propBiomassWeightFile, vlInFiles.Cells[1, 5]);

   for I := propParamOutFile to propRetroRecruitFile do
      set_Run_Prop_Str(I, vlOutFiles.Cells[1, I - propParamOutFile + 1]);

   set_IndexInput_StockTitle(ebStockTitle.Text);
   set_Run_Prop(propSearchRoutine, cbSearchRoutine.ItemIndex);
   set_Run_Prop(propProcessType, cbProcessType.ItemIndex);
   set_Run_Prop(propNumStages, round(SafeStrToFloat(ebNumStages.Text)));
   set_Run_Prop(propModelType, cbModelType.ItemIndex);
   set_Run_Prop(propISVPAControlType, round(cbISVPAControl.ItemIndex));
   set_Run_Prop(propPlusGroupMethod, cbPlusGroupMethod.ItemIndex);
   set_Run_Prop(propFirstYear, round(SafeStrToFloat(ebFirstYear.Text)));
   set_Run_Prop(propLastYear, round(SafeStrToFloat(ebLastYear.Text)));
   set_Run_Prop(propLastCatchYear, round(SafeStrToFloat(ebLastCatchYear.Text)));
   set_Run_Prop(propFirstAge, round(SafeStrToFloat(ebFirstAge.Text)));
   set_Run_Prop(propLastAge, round(SafeStrToFloat(ebLastAge.Text)));
   set_Run_Prop(propFirstRefAge, round(SafeStrToFloat(ebFirstRefAge.Text)));
   set_Run_Prop(propLastRefAge, round(SafeStrToFloat(ebLastRefAge.Text)));
   set_Run_Prop(propNumMedianElms, round(SafeStrToFloat(ebNumMedElms.Text)));
   set_Run_Prop(propSSBFracF, SafeStrToFloat(ebSSBFracF.Text));
   set_Run_Prop(propSSBFracM, SafeStrToFloat(ebSSBFracM.Text));
//   set_Run_Prop(propGammaShape, SafeStrToFloat(ebGammaShape.Text));

   NumFleetIndices := 0;
   NumSSBIndices := 0;
   NumBiomassIndices := 0;
   for I := 0 to lvIndices.Items.count - 1 do
      case TDataSourceObj(lvIndices.Items[I].Data).ObservedDataType of
         odFleet:
            NumFleetIndices := NumFleetIndices + 1;
         odSSB:
            NumSSBIndices := NumSSBIndices + 1;
         odBiomass:
            NumBiomassIndices := NumBiomassIndices + 1;
      end; // case
   set_Run_Prop(propNumFleetIndices, NumFleetIndices);
   set_Run_Prop(propNumSSBIndices, NumSSBIndices);
   set_Run_Prop(propNumBiomassIndices, NumBiomassIndices);
   NumFleetIndices := 0;
   NumSSBIndices := 0;
   NumBiomassIndices := 0;
   for I := 0 to lvIndices.Items.count - 1 do
   begin
      ds := TDataSourceObj(lvIndices.Items[I].Data);
      case ds.ObservedDataType of
         odFleet:
         begin
            DataSourceIndex := NumFleetIndices;
            NumFleetIndices := NumFleetIndices + 1;
         end;
         odSSB:
         begin
            DataSourceIndex := NumSSBIndices;
            NumSSBIndices := NumSSBIndices + 1;
         end;
         odBiomass:
         begin
            DataSourceIndex := NumBiomassIndices;
            NumBiomassIndices := NumBiomassIndices + 1;
         end;
      else
         DataSourceIndex := 0;
      end; // case
      with ds.DataSource do
         set_DataSource(ds.ObservedDataType, DataSourceIndex, FProp, MProp, ObjType, Weight, My, PlusGroupCode, BootType, Sigma, BootFile);
   end; // for
end; // TfrmRunProperties.ApplyIndexInput


procedure TfrmRunProperties.MapTableIndex(ACol, ARow : Integer; var Cat, iIndex, iYear, iAge : integer);
begin
   Cat := GetSelectedCategory;
   iIndex := 0;
   iYear := 0;
   iAge := 0;
   case Cat of
      cFYearFactor:
         iYear := ARow - 1;
      cSelection, cNatMort, cNValues:
      begin
         iYear := ARow - 1;
         iAge := ACol - 1;
      end;
      cCBL_Fac_Fleet, cCBL_Pow_Fleet:
      begin
         iIndex := max(0, cbIndex.ItemIndex);
         iYear := ARow - 1;
         iAge := ACol - 1;
      end;
      cCBL_Fac_SSB, cCBL_Fac_BM, cCBL_Pow_SSB, cCBL_Pow_BM,
         cGamma_Canum..cGamma_BM:
      begin
         iIndex := max(0, cbIndex.ItemIndex);
         iYear := ARow - 1;
      end;
   end; // case
end; // TfrmRunProperties.MapTableIndex


procedure TfrmRunProperties.UpdateParametersPage(DoFocus : Boolean);
var
   iIndex, NumIndices : Integer;
begin
   lblSurveyIndex.Enabled := GetSelectedCategory in [cCBL_Fac_Fleet, cCBL_Pow_Fleet,
      cCBL_Fac_SSB, cCBL_Pow_SSB, cCBL_Fac_BM, cCBL_Pow_BM, cGamma_Canum..cGamma_BM];
   cbIndex.Enabled := lblSurveyIndex.Enabled;
//   btnFillInTheRest.Enabled := GetSelectedCategory in [cSelection, cNatMort, cCBL_Age];
   // Setup index
   case GetSelectedCategory of
      cGamma_Canum: NumIndices := 1;
      cCBL_Fac_Fleet, cCBL_Pow_Fleet, cGamma_Fleet: NumIndices := round(get_Run_Prop(propNumFleetIndices));
      cCBL_Fac_SSB, cCBL_Pow_SSB, cGamma_SSB: NumIndices := round(get_Run_Prop(propNumSSBIndices));
      cCBL_Fac_BM, cCBL_Pow_BM, cGamma_BM: NumIndices := round(get_Run_Prop(propNumBiomassIndices));
   else
      NumIndices := 0;
   end; // case

   cbIndex.Items.Clear;
   if cbIndex.Enabled then
   begin
      for iIndex := 1 to NumIndices do
         cbIndex.Items.Add(inttostr(iIndex));
      if 0 < cbIndex.Items.Count then
         cbIndex.ItemIndex := 0;
   end;
   sgParam.Enabled := (not cbIndex.Enabled) or (0 < cbIndex.Items.Count);
   rgView.Enabled := sgParam.Enabled;
   cbIndexClick(nil);
   if DoFocus and sgParam.Enabled then
   begin
      sgParam.setFocus;
      case GetSelectedCategory of
         cNValues:
            sgParam.TopRow := sgParam.RowCount - sgParam.VisibleRowCount
      else
         sgParam.TopRow := 0;
      end;
   end;
end; // TfrmRunProperties.UpdateParametersPage


(*function TfrmRunProperties.GetParamElm(ACol, ARow : Integer) : TParamElmPtr;
var
   Cat, iIndex, iYear, iAge : Integer;
begin
   MapTableIndex(ACol, ARow, Cat, iIndex, iYear, iAge);
   Result := get_ParamElm_(Cat, iIndex, iYear, iAge)
end; // TfrmRunProperties.GetParamElm*)


function TfrmRunProperties.GetParamElmValue(ACol, ARow : Integer) : double;
var
   Cat, iIndex, iYear, iAge : Integer;
   Value : double;
begin
   MapTableIndex(ACol, ARow, Cat, iIndex, iYear, iAge);
   get_ParamElm_Value_(Cat, iIndex, iYear, iAge, Value);
   Result := Value;
end; // TfrmRunProperties.GetParamElmValue


function TfrmRunProperties.GetParamElmFlag(ACol, ARow : Integer) : Integer;
var
   Cat, iIndex, iYear, iAge, Flag : Integer;
begin
   MapTableIndex(ACol, ARow, Cat, iIndex, iYear, iAge);
   get_ParamElm_Flag_(Cat, iIndex, iYear, iAge, Flag);
   Result := Flag;
end; // TfrmRunProperties.GetParamElmFlag


function TfrmRunProperties.GetParamElmDescr(ACol, ARow : Integer) : string;
var
   Cat, iIndex, iYear, iAge : Integer;
   _Value : string50;
begin
   MapTableIndex(ACol, ARow, Cat, iIndex, iYear, iAge);
   get_ParamElm_Descr_(Cat, iIndex, iYear, iAge, _Value);
   Result := trim(_Value)
end; // TfrmRunProperties.GetParamElmDescr


procedure TfrmRunProperties.SetParamElmValue(ACol, ARow : Integer; Value : double);
var
   Cat, iIndex, iYear, iAge : Integer;
   _Value : double;
begin
   MapTableIndex(ACol, ARow, Cat, iIndex, iYear, iAge);
   _Value := Value;
   set_ParamElm_Value_(Cat, iIndex, iYear, iAge, _Value);
end; // TfrmRunProperties.GetParamElmValue


procedure TfrmRunProperties.SetParamElmFlag(ACol, ARow : Integer; Value : Integer);
var
   Cat, iIndex, iYear, iAge : Integer;
   _Value : integer;
begin
   MapTableIndex(ACol, ARow, Cat, iIndex, iYear, iAge);
   _Value := Value;
   set_ParamElm_Flag_(Cat, iIndex, iYear, iAge, _Value)
end; // TfrmRunProperties.GetParamElmFlag


procedure TfrmRunProperties.SetParamElmDescr(ACol, ARow : Integer; Value : string);
var
   Cat, iIndex, iYear, iAge : Integer;
   I : Integer;
   _Value : string50;
begin
   if Value = '' then exit;
   FillChar(_Value, sizeof(string50), ' ');
   for I := 1 to min(sizeof(string50), Length(Value)) do
      _Value[I] := Value[I];
   MapTableIndex(ACol, ARow, Cat, iIndex, iYear, iAge);
   set_ParamElm_Descr_(Cat, iIndex, iYear, iAge, _Value)
end; // TfrmRunProperties.GetParamElmDescr


function TfrmRunProperties.CanSelectCell(ACol, ARow: Integer) : Boolean;
var
   InLastAge, InLastYear, InLastCatchYear, InYoungestAgeAfterCatchYear : Boolean;
   NumCatchYears : Integer;
begin
   Result := true;
   with sgParam do
   begin
      if (0 < ARow) and (0 < ACol) and (GetSelectedCategory = cNValues) then
      begin
         NumCatchYears := round(get_Run_Prop(propLastCatchYear)) - round(get_Run_Prop(propFirstYear)) + 1;
         InLastAge := (ACol = ColCount - 2) and (ARow < RowCount);
         InLastYear := (ARow = RowCount - 1) and (ACol < ColCount - 1);
         InLastCatchYear := (ARow = NumCatchYears) and (ACol < ColCount - 1);
         InYoungestAgeAfterCatchYear := (ARow > NumCatchYears) and (ARow < RowCount - 1) and (ACol = 1);
         if not(InLastAge or InLastYear or InLastCatchYear or InYoungestAgeAfterCatchYear) then
            Result := false
      end;
   end; // with
end; // TfrmRunProperties.CanSelectCell


function TfrmRunProperties.GetSelectedCategory : Integer;
begin
   Result := Integer(cbCategory.Items.Objects[cbCategory.ItemIndex]);
end; // TfrmRunProperties.GetSelectedCategory


procedure TfrmRunProperties.UpdateStructure;
begin
   if sgParam.Enabled then
   begin
      case GetSelectedCategory of
         // Age structured
         cNValues, cSelection, cNatMort, cCBL_Fac_Fleet, cCBL_Pow_Fleet:
         begin
            sgParam.RowCount := NumYears + 1;
            sgParam.ColCount := NumAges + 1;
         end;
         // None age structured
         cFYearFactor, cCBL_Fac_SSB, cCBL_Pow_SSB, cCBL_Fac_BM, cCBL_Pow_BM:
         begin
            sgParam.RowCount := NumYears + 1;
            sgParam.ColCount := 2;
         end;
         cGamma_Canum..cGamma_BM:
         begin
            sgParam.RowCount := 2;
            sgParam.ColCount := 2;
         end;
      end; // case
      OptimizeSize;
//      sgParam.TopRow := 0;
   end
   else
   begin
      sgParam.ColCount := 2;
      sgParam.RowCount := 2;
   end;
end; // TfrmRunProperties.UpdateStructure


procedure TfrmRunProperties.VlInFilesStringsChange(Sender: TObject);
begin
   ebParamInFile.Text := vlInFiles.Cells[1,1];
end;




(*function TfrmRunProperties.GetModeValue(pParamElm : TParamElmPtr) : double;
begin
   Result := 0;
   if pParamElm <> nil then
      case rgView.ItemIndex of
         moValue: Result := pParamElm^.Value^;
         moFlag: Result := pParamElm^.Flag;
      end; // case
end; // TfrmRunProperties.GetModeValue



procedure TfrmRunProperties.SetModeValue(pParamElm : TParamElmPtr; Value : double);
begin
   if pParamElm <> nil then
      case rgView.ItemIndex of
         moValue: pParamElm^.Value^ := Value;
         moFlag: pParamElm^.Flag := round(Value);
      end; // case
end; // TfrmRunProperties.SetModeValue
*)


procedure TfrmRunProperties.OptimizeSize;
var
   MaxW : Integer;
   J, I : Integer;
   text : string;
begin
   if sgParam.Enabled then
   begin
      with sgParam do
         for J := 0 to ColCount - 1 do
         begin
            MaxW := 0;
            for I := 0 to RowCount - 1 do
            begin
               sgParamGetEditText(nil, J, I, text);
               MaxW := max(MaxW, max(Canvas.TextWidth('000'), Canvas.TextWidth(Text) + 8));
            end; // for
            ColWidths[J] := MaxW;
         end; // for
   end;
   sgParam.Invalidate;
   sgParam.Update;
end; // TfrmRunProperties.OptimizeSize


function TfrmRunProperties.GetSelectionLeft : Integer;
begin
   Result := min(sgParam.Col, m_SelTargetCol);
end; // TfrmRunProperties.GetSelectionLeft


function TfrmRunProperties.GetSelectionTop : Integer;
begin
   Result := min(sgParam.Row, m_SelTargetRow);
end; // TfrmRunProperties.GetSelectionTop


function TfrmRunProperties.GetSelectionRight : Integer;
begin
   Result := max(sgParam.Col, m_SelTargetCol);
end; // TfrmRunProperties.GetSelectionRight


function TfrmRunProperties.GetSelectionBottom : Integer;
begin
   Result := max(sgParam.Row, m_SelTargetRow);
end; // TfrmRunProperties.GetSelectionBottom


procedure TfrmRunProperties.EditCopy1Execute(Sender: TObject);
var
   s, elm : string;
   iCol, iRow : Integer;
begin
   for iRow := GetSelectionTop to GetSelectionBottom do
   begin
      for iCol := GetSelectionLeft to GetSelectionRight do
      begin
         sgParamGetEditText(nil, iCol, iRow, elm);
         s := s + elm;
         if iCol < GetSelectionRight then
            s := s + #9;
      end; // for;
      if iRow < GetSelectionBottom then
         s := s + #13#10;
   end; // for
   Clipboard.AsText := s;
end;


procedure TfrmRunProperties.EditCopy1Update(Sender: TObject);
begin
   EditCopy1.Enabled := true;
end;


type PgGridSpooler = class(PgTextSpooler)
private
   m_Grid : TStringGrid;
   m_ColOffset, m_RowOffset : Integer;
protected
   function OnCellRead : Boolean; override;
public
   constructor Create(Grid : TStringGrid; ColOffset, RowOffset : Integer); reintroduce;
end; //  PgGridSpooler


constructor PgGridSpooler.Create(Grid : TStringGrid; ColOffset, RowOffset : Integer);
begin
   inherited Create([#9], true, '');
   m_Grid := Grid;
   m_ColOffset := ColOffset;
   m_RowOffset := RowOffset;
end; // PgGridSpooler.Create


function PgGridSpooler.OnCellRead : Boolean;
var
   iCol, iRow : Integer;
begin
   iCol := min(m_Grid.ColCount, m_ColOffset + Col);
   iRow := min(m_Grid.RowCount, m_RowOffset + Row);
   m_Grid.OnSetEditText(nil, iCol, iRow, Cell);
   Result := true;
end; // PgGridSpooler.OnCellRead


procedure TfrmRunProperties.EditPaste1Execute(Sender: TObject);
var
   Spooler : PgGridSpooler;
   iRow, iCol : integer;
begin
   for iRow := GetSelectionTop to GetSelectionBottom do
   begin
      for iCol := GetSelectionLeft to GetSelectionRight do
      begin
         Spooler := PgGridSpooler.Create(sgParam, iCol, iRow);
         Spooler.Spool;
         Spooler.Free;
      end; // for
   end; // for
   OptimizeSize;
end;


procedure TfrmRunProperties.EditPaste1Update(Sender: TObject);
begin
   EditPaste1.Enabled := true;
end;


end.
